package com.scpii.api.common.auth.client;

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import com.scpii.api.common.exception.InvalidClientException;

@Component
public class ClientTokenEndpointFilter extends
		AbstractAuthenticationProcessingFilter {

	private final Logger logger = Logger
			.getLogger(ClientTokenEndpointFilter.class);

	@Resource(name = "clientAuthenticationEntryPoint")
	private AuthenticationEntryPoint authenticationEntryPoint;

	public ClientTokenEndpointFilter() {
		this("/auth/token");
	}

	@Override
	public void afterPropertiesSet() {

		super.afterPropertiesSet();
		setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
			public void onAuthenticationFailure(HttpServletRequest request,
					HttpServletResponse response,
					AuthenticationException exception) throws IOException,
					ServletException {
				if (logger.isDebugEnabled()) {
					logger.debug("Authentication Failure ", exception);
				}
				if (exception instanceof BadCredentialsException) {
					exception = new BadCredentialsException(
							exception.getMessage(),
							new InvalidClientException());
				}
				authenticationEntryPoint.commence(request, response, exception);
			}
		});
		setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
			public void onAuthenticationSuccess(HttpServletRequest request,
					HttpServletResponse response, Authentication authentication)
					throws IOException, ServletException {

			}
		});
	}

	protected ClientTokenEndpointFilter(String path) {
		super(path);
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException,
			IOException, ServletException {

		String appId = StringUtils.defaultString(request.getParameter("appId"),
				"");
		String deviceId = StringUtils.defaultString(
				request.getParameter("deviceId"), "");
		String appKey = StringUtils.defaultString(
				request.getParameter("appKey"), "");

		appId = appId.trim();
		ClientAuthenticationToken authRequest = new ClientAuthenticationToken(
				appId, appKey, deviceId);

		return this.getAuthenticationManager().authenticate(authRequest);
	}

	@Override
	protected void successfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain,
			Authentication authResult) throws IOException, ServletException {
		super.successfulAuthentication(request, response, chain, authResult);
		chain.doFilter(request, response);
	}

	@Override
	protected boolean requiresAuthentication(HttpServletRequest request,
			HttpServletResponse response) {
		String uri = request.getRequestURI();
		int pathParamIndex = uri.indexOf(';');
		if (pathParamIndex > 0) {
			uri = uri.substring(0, pathParamIndex);
		}
		String appId = request.getParameter("appId");
		if (appId == null) {
			return false;
		}

		String appKey = request.getParameter("appKey");
		if (appKey == null) {
			return false;
		}

		String deviceId = request.getParameter("deviceId");
		if (deviceId == null) {
			return false;
		}
		return super.requiresAuthentication(request, response);
	}

	@Resource(name = "clientAuthenticationManager")
	@Override
	public void setAuthenticationManager(
			AuthenticationManager authenticationManager) {
		super.setAuthenticationManager(authenticationManager);
	}

}
